package cn.t.facade.user;


import cn.t.constants.CommonConstants;
import cn.t.converter.user.UserInfoRequestConverter;
import cn.t.converter.user.UserSessionVOConverter;
import cn.t.core.exception.BizException;
import cn.t.core.mode.YesNoEnum;
import cn.t.dto.android.CallbackDTO;
import cn.t.core.enums.base.BaseStatusEnum;
import cn.t.core.enums.base.CommonError;
import cn.t.enums.user.AndriodLoginTypeEnum;
import cn.t.enums.user.PassportTypeEnum;
import cn.t.enums.user.RoleTypeEnum;
import cn.t.enums.user.ScenarioCodeEnum;
import cn.t.enums.user.UserError;
import cn.t.facade.android.AndroidSessionFacade;
import cn.t.facade.device.DeviceFacade;
import cn.t.model.IndustryUserInfoDO;
import cn.t.model.device.DeviceDO;
import cn.t.model.user.CustomerFirmDO;
import cn.t.model.user.UserPassportDO;
import cn.t.model.user.UserQueryDO;
import cn.t.request.api.SSOLoginReq;
import cn.t.response.ResultDTO;
import cn.t.service.IndustryUserInfoService;
import cn.t.service.device.DeviceService;
import cn.t.service.user.CustomerFirmService;
import cn.t.service.user.UserPassportService;
import cn.t.service.user.UserQueryService;
import cn.t.utils.CardNumAnalysisUtil;
import cn.t.vo.andriod.AndroidDeviceVO;
import cn.t.vo.user.RoleVO;
import cn.t.vo.user.UserSessionVO;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;


/**
 * @author l
 */
@Slf4j
@Service
public class UserLoginFacade {

    private final ConcurrentHashMap<Long, CompletableFuture<ResultDTO>> futures = new ConcurrentHashMap<>();

    public UserSessionVO loginByPhonePassword(Long deviceId, String phoneNumber, String password, AndriodLoginTypeEnum type) {
        return new DeviceLoginHelper(deviceId, PassportTypeEnum.PHONE_NUMBER, phoneNumber, password) {
            @Override
            public UserPassportDO getUserPassport(Long firmId, String passportValue) {
                return passportService.getUserPassportByPhoneNumber(passportValue);
            }

            @Override
            public boolean isValidate(UserPassportDO userPassport, String password) {
                passportService.checkPassword(userPassport, password);
                return true;
            }
        }.login(type);
    }


    public UserSessionVO loginByCardEmployeePassword(Long deviceId, String employeeCode, String password, AndriodLoginTypeEnum type) {
        return new DeviceLoginHelper(deviceId, PassportTypeEnum.EMP_CODE, employeeCode, password) {
            @Override
            public UserPassportDO getUserPassport(Long firmId, String passportValue) {
                return passportService.getUserPassportByEmployeeCode(firmId, passportValue);
            }

            @Override
            public boolean isValidate(UserPassportDO userPassport, String password) {
                passportService.checkPassword(userPassport, password);
                return true;
            }
        }.login(type);
    }


    public UserSessionVO loginByCard(Long deviceId, String cardCode, AndriodLoginTypeEnum type) {
        return new DeviceLoginHelper(deviceId, PassportTypeEnum.CARD_CODE, cardCode, null) {
            @Override
            public UserPassportDO getUserPassport(Long firmId, String passportValue) {
                Integer cardReaderId = this.getDevice().getCardReaderId();
                if (cardReaderId == null) {
                    String template = "指定的设备未维护的卡读取器，设备id：%s，卡号：%s";
                    String message = String.format(template, deviceId, passportValue);

                    throw new BizException(CommonError.ILLEGAL_PARAMETER, message);
                }
                String cardCode = CardNumAnalysisUtil.getCardNum(cardReaderId, passportValue);

                return passportService.getUserPassportByCardCode(firmId, cardCode);
            }

            @Override
            public boolean isValidate(UserPassportDO userPassport, String password) {
                return true;
            }
        }.login(type);

    }

    /**
     * 卡号登录
     *
     * @param deviceId
     * @param cardCode
     * @return
     */
    public UserSessionVO loginByScanCode(Long deviceId, String cardCode,AndriodLoginTypeEnum type) {
        return new DeviceLoginHelper(deviceId, PassportTypeEnum.EMP_CODE, cardCode, null) {
            @Override
            public UserPassportDO getUserPassport(Long firmId, String employeeCode) {

                List<UserQueryDO> userQueryList = userQueryService.findByEmployeeCode(firmId, employeeCode);
                if (CollectionUtils.isEmpty(userQueryList)) {
                    log.error("未找到该工号对应的用户，工号：{}", employeeCode);
                    throw new BizException(UserError.DUPLICATED_PASSPORT, "用户未注册智能柜柜！");
                }

                Set<Long> userIds = userQueryList.stream().map(UserQueryDO::getId).collect(Collectors.toSet());
                if (CollectionUtils.isEmpty(userIds)) {
                    log.error("登录异常，工号重，工号：{}", employeeCode);
                    throw new BizException(UserError.DUPLICATED_PASSPORT, "登录异常，用户信息重复！");
                }

                UserPassportDO dummy = new UserPassportDO();
                dummy.setUserId(userQueryList.get(0).getId());
                dummy.setId(99999999L);
                dummy.setFirmId(firmId);
                dummy.setIsDeleted(YesNoEnum.FALSE);
                dummy.setPassportStatus(String.valueOf(BaseStatusEnum.AVAILABLE.getCode()));

                return dummy;
            }

            @Override
            public boolean isValidate(UserPassportDO userPassport, String password) {
                return true;
            }
        }.login(type);
    }

    public UserSessionVO loginByPhoneLastFour(Long deviceId, String phoneNumber, AndriodLoginTypeEnum type) {
        return new DeviceLoginHelper(deviceId, PassportTypeEnum.PHONE_NUMBER, phoneNumber, phoneNumber) {
            @Override
            public UserPassportDO getUserPassport(Long firmId, String passportValue) {

                IndustryUserInfoDO industryUserInfoDO = industryUserInfoService.getIndustryUserInfo(passportValue);
                if (industryUserInfoDO == null || industryUserInfoDO.getUserId() == null || industryUserInfoDO.getUserId() <= 0L) {
                    log.warn("用户名不存在 phoneNumber：{}", passportValue);
                    throw new BizException(UserError.PASSPORT_IS_NOT_EXISTS, UserError.PASSPORT_IS_NOT_EXISTS.getName());
                }

                UserQueryDO userInfoDO = userQueryService.findByUserId(firmId, industryUserInfoDO.getUserId(), true);
                if (userInfoDO == null || userInfoDO.getId() == null || userInfoDO.getId() <= 0L) {
                    log.warn("用户名不存在 phoneNumber：{}", passportValue);
                    throw new BizException(UserError.PASSPORT_IS_NOT_EXISTS, UserError.PASSPORT_IS_NOT_EXISTS.getName());
                }

                UserPassportDO dummy = new UserPassportDO();
                dummy.setUserId(industryUserInfoDO.getUserId());
                dummy.setId(99999999L);
                dummy.setFirmId(firmId);
                dummy.setIsDeleted(YesNoEnum.FALSE);
                dummy.setPassportStatus(String.valueOf(BaseStatusEnum.AVAILABLE.getCode()));

                return dummy;

            }

            @Override
            public boolean isValidate(UserPassportDO userPassport, String password) {
                return true;
            }
        }.login(type);
    }

    public UserSessionVO loginByCardEmployee(Long deviceId, String cardCode, String password, AndriodLoginTypeEnum type) {
        return new DeviceLoginHelper(deviceId, PassportTypeEnum.CARD_CODE, cardCode, password) {
            @Override
            public UserPassportDO getUserPassport(Long firmId, String passportValue) {
                return passportService.getUserPassportByCardCode(firmId, passportValue);
            }

            @Override
            public boolean isValidate(UserPassportDO userPassport, String password) {
                List<UserPassportDO> passports = passportService.findByUserId(userPassport.getUserId());
                if (CollectionUtils.isEmpty(passports)) {
                    return false;
                }

                for (UserPassportDO passport : passports) {
                    if (!PassportTypeEnum.EMP_CODE.getCode().equals(passport.getPassportType())) {
                        continue;
                    }

                    if (passport.getPassportValue().toLowerCase().endsWith(password.toLowerCase())) {
                        return true;
                    }
                }

                return false;
            }
        }.login(type);
    }


    public UserSessionVO loginByUserNamePassword(Long deviceId, String userName, String password, AndriodLoginTypeEnum type) {
        return new DeviceLoginHelper(deviceId, PassportTypeEnum.USER_NAME, userName, password) {
            @Override
            public UserPassportDO getUserPassport(Long firmId, String passportValue) {
                List<UserQueryDO> userQueryList = userQueryService.findByUserName(firmId, passportValue);
                if (CollectionUtils.isEmpty(userQueryList)) {
                    log.warn("用户名不存在 userName：{}", passportValue);
                    throw new BizException(UserError.DUPLICATED_PASSPORT, UserError.DUPLICATED_PASSPORT.getName());
                } else if (userQueryList.size() > 1) {
                    log.warn("用户名存在多个 userName：{}", passportValue);
                    throw new BizException(UserError.DUPLICATED_PASSPORT, UserError.DUPLICATED_PASSPORT.getName());
                }

                CustomerFirmDO firm = customerFirmService.findById(firmId);


                return passportService.getUserPassportByUserName(passportValue);
            }

            @Override
            public boolean isValidate(UserPassportDO userPassport, String password) {
                passportService.checkPassword(userPassport, password);
                return true;
            }
        }.login(type);
    }


    public UserSessionVO loginByFace(Long deviceId, Long faceUserId, AndriodLoginTypeEnum type) {
        return new DeviceLoginHelper(deviceId, PassportTypeEnum.FACE, String.valueOf(faceUserId), null) {
            @Override
            public UserPassportDO getUserPassport(Long firmId, String passportValue) {

                UserQueryDO userQueryDO = userQueryService.findByUserId(firmId, faceUserId, true);
                if (userQueryDO == null || userQueryDO.getId() == null || !userQueryDO.getId().equals(faceUserId)) {
                    log.warn("用户名不存在 用户ID：{}", faceUserId);
                    throw new BizException(UserError.PASSPORT_IS_NOT_EXISTS, UserError.PASSPORT_IS_NOT_EXISTS.getName());
                }

                UserPassportDO dummy = new UserPassportDO();
                dummy.setUserId(faceUserId);
                dummy.setId(99999999L);
                dummy.setFirmId(firmId);
                dummy.setIsDeleted(YesNoEnum.FALSE);
                dummy.setPassportStatus(String.valueOf(BaseStatusEnum.AVAILABLE.getCode()));

                return dummy;
            }

            @Override
            public boolean isValidate(UserPassportDO userPassport, String password) {
                return true;
            }
        }.login(type);

    }


    public UserSessionVO login(Integer scenarioCode, String username, String password) {
        UserPassportDO passportDO = passportService.checkPassword(username, password);
        UserSessionVO userSessionVO = combineData(scenarioCode, passportDO);
        userSessionFacade.login(userSessionVO);
        return userSessionVO;
    }



    public UserSessionVO login(Integer scenarioCode, String phoneNumber, Integer verifyCode) {
        UserPassportDO passportDO = passportService.checkMessageCode(phoneNumber, verifyCode);
        UserSessionVO userSessionVO = combineData(scenarioCode, passportDO);
        userSessionFacade.login(userSessionVO);
        return userSessionVO;
    }

    public UserSessionVO combineData(Integer scenarioCode, UserPassportDO passport) {
        UserSessionVO session = userSessionVOConverter.passportToSession(passport);
        session = userQueryFacade.combineSession(scenarioCode, session);
        return session;
    }

    public void logout() {
        userSessionFacade.removeSession();
    }


    @AllArgsConstructor
    @Data
    private abstract class DeviceLoginHelper {


        public DeviceLoginHelper(Long deviceId, PassportTypeEnum passportType, String passportValue, String password) {
            this.deviceId = deviceId;
            this.passportType = passportType;
            this.passportValue = passportValue;
            this.password = password;
            this.device = deviceService.findById(deviceId);
            if (device == null) {
                String errorMessage = String.format("设备不存在. 设备号=%s", deviceId);
                log.warn(errorMessage);
                throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
            }
        }

        public UserSessionVO login( AndriodLoginTypeEnum  type) {

            this.firmId = device.getFirmId();

            UserPassportDO userPassport = getUserPassport(firmId, passportValue);
            if (userPassport == null || userPassport.getUserId() == null) {
                throw new BizException(UserError.PASSPORT_IS_NOT_EXISTS, UserError.PASSPORT_IS_NOT_EXISTS.getName());
            }
            if (!String.valueOf(BaseStatusEnum.AVAILABLE.getCode()).equals(userPassport.getPassportStatus())) {
                throw new BizException(UserError.PASSPORT_IS_NOT_AVAILABLE, UserError.PASSPORT_IS_NOT_AVAILABLE.getName());
            }

            boolean validated = isValidate(userPassport, password);
            if (!validated) {
                throw new BizException(UserError.VALIDATE_PASSWORD_FAILED, UserError.VALIDATE_PASSWORD_FAILED.getName());
            }

            androidSessionFacade.devicePickUp(userPassport.getUserId(), firmId);


            UserSessionVO userSessionVO = combineData(ScenarioCodeEnum.MATERIAL_ISSUE.getCode(), userPassport);
            //领料登录需要校验设备权限
            if (AndriodLoginTypeEnum.pickUpRole.contains(type.getCode())){
                Set<Long> deviceIdList = userSessionFacade.getDeviceIdList(userSessionVO,firmId, RoleTypeEnum.MATERIAL_ISSUE);
                if (!deviceIdList.contains(deviceId)) {
                    throw new BizException(UserError.PERMISSION_DENIED, UserError.PERMISSION_DENIED.getName());
                }
            }
            //管理员登录必须有管理员权限
            if (AndriodLoginTypeEnum.ANDROID_ADMIN_LOGIN.equals(type)){
                List<RoleVO> roleList = userSessionFacade.getRoleList(userSessionVO, null);
                boolean b = roleList.stream().anyMatch(roleVO -> roleVO.getRoleType().equals(RoleTypeEnum.SYSTEM.getCode()));
                if (!b){
                    throw new BizException(UserError.PERMISSION_DENIED, UserError.PERMISSION_DENIED.getName());
                }
            }

            userSessionVO.setDeceiveId(deviceId);
            userSessionFacade.login(userSessionVO);
            return userSessionVO;
        }


        //
        public abstract UserPassportDO getUserPassport(Long firmId, String passportValue);

        public abstract boolean isValidate(UserPassportDO userPassport, String password);

        private Long deviceId;
        private PassportTypeEnum passportType;
        private String passportValue;
        private String password;
        private Long firmId;
        private DeviceDO device;
    }


    /**
     * 设备登录成功回调
     */
    public void deviceLoginCallback(CallbackDTO callbackDTO, AndroidDeviceVO device) {
        ResultDTO result = new ResultDTO();
        result.setResult(0);
        Long deviceId = device.getDeviceId();
        // 成功
        if ("1".equals(callbackDTO.getStatus())) {

            CompletableFuture<ResultDTO> future = futures.remove(deviceId);
            if (future != null) {
                result.setResult(1);
                future.complete(result);
            } else {
                log.warn("No pending request for device ID: {}", deviceId);
            }
        } else {
            log.error("Unexpected response: {}", callbackDTO);
            CompletableFuture<ResultDTO> future = futures.remove(deviceId);
            if (future != null) {
                result.setFailedReason("设备登录失败");
                future.complete(result);
            }
        }
    }

    @Autowired
    private AndroidSessionFacade androidSessionFacade;


    @Autowired
    private UserSessionFacade userSessionFacade;

    @Autowired
    private UserPassportService passportService;

    @Autowired
    private UserSessionVOConverter userSessionVOConverter;

    @Autowired
    private UserQueryFacade userQueryFacade;

    @Autowired
    private DeviceService deviceService;
    @Autowired
    private UserQueryService userQueryService;

    @Autowired
    private IndustryUserInfoService industryUserInfoService;


    @Resource
    private CustomerFirmService customerFirmService;


}
